/**
 ******************************************************************************
 * @file	interface/stm32-spi.c
 * @brief	TR700-STM32 spi 通信
 *
 * 详细协议格式参看 《TR700-RM》
 * https://git.oschina.net/glinklib/tr700-stm32/doc/TR700-RM.md
 *
 * Copyright (C) [2017] <桂林聚联科技有限公司, Inc.> All Rights Reserved.
 *
 *
 * @section Platform
 *	-# linux-2.6
 * @section Library
 *	-# null
 *
 * @section Depend
 *	-# spi_mxs.ko
 *	-# spidev.ko
 *	-# libpthread.so
 *
 * - 2017-6-22,MenglongWu,MenglongWoo@aliyun.com
 */

#include <autoconfig.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>

#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

#include "proginfo.h"
#include "stm32-spi.h"  // 应用层
#include "printl.h"


#define SPI_TP_BEGIN  _IOR(SPI_IOC_MAGIC, 5, __u8)
#define SPI_TP_COMMIT _IOR(SPI_IOC_MAGIC, 6, __u8)

#ifdef NDEBUG
#define dbg_this(fmt, ...)
#else
#define dbg_this(fmt, ...) PRINTL(STM32SPI_DBG_LEVEL,   \
                                  C_DEBUG fmt C_NORMAL, \
                                  ##__VA_ARGS__)
#endif

#ifdef CONFIG_USE_PTHREAD_FPGA_OTDR
#define mutex_init(x, y) pthread_mutex_init((x), (y))
#define mutex_destroy(x) pthread_mutex_destroy((x))
#define mutex_lock(x)                \
    ioctl(dev->fd, SPI_TP_BEGIN, 0); \
    pthread_mutex_lock((x));
#define mutex_unlock(x)        \
    pthread_mutex_unlock((x)); \
    ioctl(dev->fd, SPI_TP_COMMIT, 0);
#else
#define mutex_init(x, y)
#define mutex_destroy(x)
#define mutex_lock(x)   ioctl(dev->fd, SPI_TP_BEGIN, 0);
#define mutex_unlock(x) ioctl(dev->fd, SPI_TP_COMMIT, 0);
#endif

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static const char *dev_desc = "stm32-spi";

/* 数据错误试着次数 */
#define RETRY (3)


/* 本接口可支持的软件版本 */
struct _stm32_spi_table
{
    unsigned long soft_ver;
    unsigned long hw_ver;
    char	 *desc;
};

#if defined(CONFIG_STM32SPI_PRINT_TX) || defined(CONFIG_STM32SPI_PRINT_RX)
static void PrintfMemory(uint8_t *buf, uint32_t len)
{
    for (uint32_t i = 0; i < len; i++) {
	if (i & 0xf) {
	    printf(" ");
	}
	else {
	    printf("\r\n");
	}
	printf("%2.2x", (unsigned char)*(buf + i));
    }
    printf("\r\n");
}
#endif


#if CONFIG_STM32SPI_PRINT_TX
struct on_active_list
{
    char *cmd_name;
};
struct on_active_list active_list[] = {
    { "CMD_UNDEFINE" },
    { "CMD_ALIVE" },
    { "CMD_GETENV_PRE" },
    { "CMD_GETENV" },
    { "CMD_SETENV" },
    { "CMD_SAVEENV" },
    { "CMD_SETLS" },
    { "CMD_OPM_W" },
    { "CMD_OPM_R" },
    { "CMD_DBG" },
    { "CMD_OPM_R_DBG" },
    { "CMD_OPM_W_DBG" },
    { "CMD_SETLS_DBG" },
    { "CMD_GETLS_DBG" },
};


void _show_cmd_name(char cmd)
{
    if (cmd >= sizeof(active_list) / sizeof(struct on_active_list)) {
	printf("unknow %x\r\n", cmd);
	return;
    }
    printf("        %s\n", active_list[cmd].cmd_name);
}
#endif

int stm_close(struct stm32_spi_dev *dev)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    mutex_destroy(&dev->mutex);
    close(dev->fd);
    free(dev);
    dev = NULL;
    return 0;
}


int stm_open(char *device, struct stm32_spi_dev **dev, unsigned long ispeed)
{
    // todo spinlock
    unsigned char mode  = 0;
    unsigned char bits  = 8;
    unsigned long speed = 100 * 1000;  // 100KHz
    int           fd;

    if (ispeed) {
	speed = ispeed;
    }

    fd = open(device, O_RDWR);
    if (fd == 0) {
	return -1;
    }

    /*
      SPI_MODE_0:
        SPI_CPOL_Low
        SPI_CPHA_1Edge
     */
    mode = SPI_MODE_0;
    ioctl(fd, SPI_IOC_WR_MODE, &mode);
    ioctl(fd, SPI_IOC_RD_MODE, &mode);
    ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

    struct stm32_spi_dev *pdev;
    pdev = (struct stm32_spi_dev *)malloc(sizeof(struct stm32_spi_dev));

    if (pdev == NULL) {
	goto _fail1;
    }
    bzero(pdev, sizeof(struct stm32_spi_dev));

    pdev->fd = fd;

    mutex_init(&pdev->mutex, NULL);
    if (-1 == stm_alive(pdev)) {
	goto _fail2;
    }
    *dev = pdev;
    // stm_ls_wavelist(pdev, NULL, 0);
    return 0;
_fail1:
    close(fd);
    return -1;
_fail2:
    stm_close(pdev);
    return -2;
}


unsigned int _stm_transfer(struct stm32_spi_dev *dev,
                           char                 *tbuf1,
                           int                   tlen1,
                           char                 *tbuf2,
                           int                   tlen2,
                           char                 *rbuf,
                           int                   rlen)
{
    struct spi_ioc_transfer arr[] = {
	{
		.tx_buf      = (unsigned long)tbuf1,
		.rx_buf      = (unsigned long)NULL,
		.len         = tlen1,
		.cs_change   = 0,
		.delay_usecs = 500,
	},
	{
		.tx_buf      = (unsigned long)tbuf2,
		.rx_buf      = (unsigned long)NULL,
		.len         = tlen2,
		.cs_change   = 0,
		.delay_usecs = 500,
	},
	{
		.tx_buf    = (unsigned long)NULL,
		.rx_buf    = (unsigned long)rbuf,
		.len       = rlen,
		.cs_change = 1,
	},
    };

#if CONFIG_STM32SPI_PRINT_TX
    if (STM32SPI_DBG_TX) {
	printf("\n*****************************");
	_show_cmd_name(OFFSET_CMD(tbuf1));
	dbg_this("hdr : %d byte", tlen1);
	PrintfMemory((uint8_t *)tbuf1, tlen1);
	dbg_this("data: %d byte", tlen2);
	PrintfMemory((uint8_t *)tbuf2, tlen2);
    }
#endif
    ioctl(dev->fd, SPI_IOC_MESSAGE(ARRAY_SIZE(arr)), &arr);


    usleep(1000);
#if CONFIG_STM32SPI_PRINT_RX
    if (STM32SPI_DBG_RX) {
	dbg_this("rx  : %d byte", rlen);
	PrintfMemory((uint8_t *)rbuf, rlen);
    }
#endif
    return 0;
}


char chip_status = CTX_F_SUCCESS;
int  _check_common_rx(struct tr700_common_tx *ctx,
                      struct tr700_common_rx *rbuf,
                      char                   *fun_name)
{
    // printf("%x %x\r\n", rbuf->cmd , ctx->cmd);
    if (rbuf->cmd != ctx->cmd) {
	PRINTE("%s() unmatch r %x t %x\r\n", fun_name, rbuf->cmd, ctx->cmd);
	chip_status = CTX_F_BUSY;
	return -1;
    }

    switch (rbuf->status) {
    case 0x00:
	// dbg_this("%s() success\r\n", fun_name);
	chip_status = CTX_F_SUCCESS;
	return 0;
    case 0x80:
#if defined(CONFIG_STM32SPI_PRINT_BUSY)
	if (STM32SPI_DBG_BUSY) {
	    PRINTW("%s() busy\r\n", fun_name);
	}
#endif
	chip_status = CTX_F_BUSY;
	return -1;
    case 0x01:
	PRINTW("%s() cmd error\r\n", fun_name);
	chip_status = CTX_F_ERR;
	return -1;
    default:
	PRINTE("%s unknow\r\n", fun_name);
	return -1;
    }
}


int _stm_alive(struct stm32_spi_dev *dev)
{
    assert(dev != NULL);
    dev->desc = (char *)dev_desc;

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_ALIVE,
	.len  = 0,
    };
    struct tr700_common_rx rbuf;

    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              (char *)NULL,
	              0,
	              (char *)&rbuf,
	              sizeof(struct tr700_common_tx));
	mutex_unlock(&dev->mutex);

	if (-1 == _check_common_rx(&ctx, &rbuf, (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		sleep(1);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	return 0;
    }
    return -1;
}
int stm_alive(struct stm32_spi_dev *dev)
{
    mutex_lock(&dev->mutex);
    int ret = _stm_alive(dev);
    mutex_unlock(&dev->mutex);
    return ret;
}


int stm_setls(struct stm32_spi_dev *dev, struct tr700_setls_tx *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    assert(val != NULL);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_SETLS,
	.len  = sizeof(struct tr700_setls_tx),
    };
    struct tr700_setls_tx txval = {
	.ch   = val->ch,
	.mode = val->mode,
	.dbm  = val->dbm,
    };
    struct tr700_common_rx rbuf;


    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              (char *)&txval,
	              sizeof(struct tr700_setls_tx),
	              (char *)&rbuf,
	              sizeof(struct tr700_common_tx));
	mutex_unlock(&dev->mutex);

	if (-1 == _check_common_rx(&ctx, &rbuf, (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		usleep(50000);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	return 0;
    }
    return 0;
}


int stm_setls_dbg(struct stm32_spi_dev *dev, struct tr700_setls_dbg_tx *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    assert(val != NULL);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_SETLS_DBG,
	.len  = sizeof(struct tr700_setls_dbg_tx),
    };
    struct tr700_setls_dbg_tx txval = {
	.ch   = val->ch,
	.mode = val->mode,
	.dac  = val->dac,
    };
    struct tr700_common_rx rbuf;


    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              (char *)&txval,
	              sizeof(struct tr700_setls_dbg_tx),
	              (char *)&rbuf,
	              sizeof(struct tr700_common_tx));
	mutex_unlock(&dev->mutex);

	if (-1 == _check_common_rx(&ctx, &rbuf, (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		sleep(1);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	return 0;
    }
    return 0;
}

int stm_getls_dbg(struct stm32_spi_dev *dev, struct tr700_getls_dbg *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    assert(val != NULL);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_GETLS_DBG,
	.len  = 0,
    };

    struct tr700_getls_dbg_rx rbuf;


    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              NULL,
	              0,
	              (char *)&rbuf,
	              sizeof(struct tr700_getls_dbg_rx));
	mutex_unlock(&dev->mutex);

	if (-1 == _check_common_rx(&ctx,
	                           (struct tr700_common_rx *)&rbuf,
	                           (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		usleep(50000);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	val->ch   = rbuf.ch;
	val->mode = rbuf.mode;
	val->adc  = rbuf.adc;
	val->dac  = rbuf.dac;
	return 0;
    }
    return 0;
}

static float __get_detaref(struct stm32_spi_dev *dev, short wave)
{
    char  val[PRE_ENV_LEN] = { 0 };
    char *penv             = "_1550_ref_1310";

    switch (wave) {
    case 1625:
	penv = "_1625_ref_1310";
	break;
    case 1550:
	penv = "_1550_ref_1310";
	break;
    case 980:
	penv = "_980_ref_1310";
	break;
    case 850:
	penv = "_850_ref_1310";
	break;
    case 640:
	penv = "_850_ref_1310";
	break;
    case 1480:
	penv = "_1480_ref_1310";
	break;
    case 1490:
	penv = "_1490_ref_1310";
	break;
    default:
	return 1;
    }

    if (0 == stm_getenv(dev, penv, &val)) {
	return atof(val);
    }
    return 1;
}
int stm_getopm(struct stm32_spi_dev *dev, struct tr700_getopm *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    assert(val != NULL);

#if 1
    static float deta_ref  = 1;
    static int   last_wave = 1310;
#endif
    // if (last_wave != val->wave) {
    deta_ref  = __get_detaref(dev, val->wave);
    last_wave = val->wave;
    // }
    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_OPM_R,
	.len  = 0,
    };

    struct tr700_getopm_rx rbuf;


    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              NULL,
	              0,
	              (char *)&rbuf,
	              sizeof(struct tr700_getopm_rx));
	mutex_unlock(&dev->mutex);

	if (-1 == _check_common_rx(&ctx,
	                           (struct tr700_common_rx *)&rbuf,
	                           (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		usleep(50000);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	val->dbm  = rbuf.dbm * deta_ref;
	val->wave = rbuf.wave;
	val->mode = rbuf.mode;
	return 0;
    }
    return 0;
}

int stm_setenv(struct stm32_spi_dev *dev, char *env, char *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_SETENV,
    };
    struct tr700_setenv_tx txval = { 0 };
    struct tr700_common_rx rbuf;

    snprintf(txval.env, PRE_ENV_LEN, "%s=%s", env, val);
    ctx.len = strlen(txval.env) + 1;


    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              (char *)&txval,
	              ctx.len,
	              (char *)&rbuf,
	              sizeof(struct tr700_common_rx));
	mutex_unlock(&dev->mutex);
	if (-1 == _check_common_rx(&ctx, &rbuf, (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		// sleep(1);
		usleep(50000);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	return 0;
    }
    return 0;
}

int stm_getenv(struct stm32_spi_dev *dev, char *env, char (*val)[PRE_ENV_LEN])
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_GETENV_PRE,
    };
    struct tr700_getenv_tx txval = { 0 };


    {
	struct tr700_common_rx rbuf;

	snprintf(txval.env, PRE_ENV_LEN, "%s", env);
	ctx.len = strlen(txval.env) + 1;


	for (int i = 0; i < RETRY; i++) {
	    mutex_unlock(&dev->mutex);
	    _stm_transfer(dev,
	                  (char *)&ctx,
	                  sizeof(struct tr700_common_tx),
	                  (char *)&txval,
	                  ctx.len,
	                  (char *)&rbuf,
	                  sizeof(struct tr700_common_rx));
	    mutex_unlock(&dev->mutex);

	    if (-1 == _check_common_rx(&ctx, &rbuf, (char *)__FUNCTION__)) {
		if (CTX_F_BUSY == chip_status) {
		    sleep(1);
		    continue;
		}
		else {
		    return -1;
		}
	    }
	    break;
	}
    }
    usleep(20000);
    {
	for (int i = 0; i < RETRY; i++) {
	    struct tr700_getenv_rx rbuf;

	    ctx.cmd = CMD_GETENV;
	    ctx.len = 0;
	    mutex_unlock(&dev->mutex);
	    _stm_transfer(dev,
	                  (char *)&ctx,
	                  sizeof(struct tr700_common_tx),
	                  NULL,
	                  0,
	                  (char *)&rbuf,
	                  sizeof(struct tr700_getenv_rx));
	    mutex_unlock(&dev->mutex);

	    if (-1 == _check_common_rx(&ctx,
	                               (struct tr700_common_rx *)&rbuf,
	                               (char *)__FUNCTION__)) {
		if (CTX_F_BUSY == chip_status) {
		    sleep(1);
		    continue;
		}
		else {
		    return -1;
		}
	    }
	    memcpy(val, &rbuf.env, PRE_ENV_LEN);
	    return 0;
	}
    }

    return 0;
}

int stm_saveenv(struct stm32_spi_dev *dev)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_SAVEENV,
	.len  = 0,
    };
    struct tr700_common_rx rbuf;

    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              NULL,
	              0,
	              (char *)&rbuf,
	              sizeof(struct tr700_common_tx));
	mutex_unlock(&dev->mutex);

	if (-1 == _check_common_rx(&ctx, &rbuf, (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		usleep(50000);
		continue;
	    }
	    else {
		return -1;
	    }
	    return -1;
	}
    }
    return 0;
}

int stm_debug(struct stm32_spi_dev *dev, int dbg)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_DBG,
    };
    struct tr700_dbg_tx    txval = { 0 };
    struct tr700_common_rx rbuf;

    ctx.len       = sizeof(struct tr700_dbg_tx);
    txval.isdebug = dbg;
    // printf("%d debug \r\n", dbg);


    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              (char *)&txval,
	              ctx.len,
	              (char *)&rbuf,
	              sizeof(struct tr700_common_rx));
	mutex_unlock(&dev->mutex);
	if (-1 == _check_common_rx(&ctx, &rbuf, (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		usleep(50000);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	return 0;
    }
    return 0;
}

int stm_setopm(struct stm32_spi_dev *dev, struct tr700_setopm *val)
{
    return 0;
}
int stm_setopm_param(struct stm32_spi_dev *dev, int level)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_OPM_W_DBG,
    };
    struct tr700_opm_set_tx txval = { 0 };
    struct tr700_common_rx  rbuf;

    ctx.len     = sizeof(struct tr700_opm_set_tx);
    txval.level = level;


    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              (char *)&txval,
	              ctx.len,
	              (char *)&rbuf,
	              sizeof(struct tr700_common_rx));
	mutex_unlock(&dev->mutex);
	if (-1 == _check_common_rx(&ctx, &rbuf, (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		usleep(50000);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	return 0;
    }
    return 0;
}

// int stm_getopm_dbg(struct stm32_spi_dev *dev, struct tr700_getopm_dbg *val)
int stm_getopm_dbg(struct stm32_spi_dev *dev, struct tr700_getopm_dbg *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    assert(val != NULL);

    struct tr700_common_tx ctx = {
	.flag = 'S',
	.addr = 0xf1,
	.cmd  = CMD_OPM_R_DBG,
	.len  = 0,
    };

    struct tr700_getopm_dbg_rx rbuf;


    for (int i = 0; i < RETRY; i++) {
	mutex_unlock(&dev->mutex);
	_stm_transfer(dev,
	              (char *)&ctx,
	              sizeof(struct tr700_common_tx),
	              NULL,
	              0,
	              (char *)&rbuf,
	              sizeof(struct tr700_getopm_rx));
	mutex_unlock(&dev->mutex);

	if (-1 == _check_common_rx(&ctx,
	                           (struct tr700_common_rx *)&rbuf,
	                           (char *)__FUNCTION__)) {
	    if (CTX_F_BUSY == chip_status) {
		sleep(1);
		continue;
	    }
	    else {
		return -1;
	    }
	}
	val->level = rbuf.level;
	val->adc   = rbuf.adc;
	val->dbm   = rbuf.dbm;
	return 0;
    }
    return 0;
}


// misc

// 返回值 -1 错误，1310，1550
int stm_ch2wave(struct stm32_spi_dev *dev, int ch)
{
    struct wave_list *plist = (struct wave_list *)&dev->wl;

    for (int i = 0; i < 3; i++) {
	if (plist->ch == ch) {
	    return plist->wave;
	}
	plist++;
    }
    return 0;
}
// 返回值 -1 错误，1,2,3
int stm_wave2ch(struct stm32_spi_dev *dev, int wave)
{
    struct wave_list *plist = (struct wave_list *)&dev->wl;

    for (int i = 0; i < 3; i++) {
	if (plist->wave == wave) {
	    return plist->ch;
	}
	plist++;
    }
    return 0;
}

// 关闭光源
int stm_ls_off(struct stm32_spi_dev *dev)
{
    struct tr700_setls_tx val;
    val.ch = LS_CH_OFF;
    return stm_setls(dev, &val);
}

// list

int stm_ls_wavelist(struct stm32_spi_dev *dev, struct wave_list *list, int count)
{
    char              val[PRE_ENV_LEN] = { 0 };
    struct wave_list *plist            = (struct wave_list *)&dev->wl;


    stm_getenv(dev, "ch1_en", &val);
    if (atoi(val)) {
	stm_getenv(dev, "ch1_wave", &val);
	plist->ch   = 1;
	plist->wave = atoi(val);
    }
    else {
	plist->ch   = 0;
	plist->wave = 0;
    }
    plist++;

    stm_getenv(dev, "ch2_en", &val);
    if (atoi(val)) {
	stm_getenv(dev, "ch2_wave", &val);
	plist->ch   = 2;
	plist->wave = atoi(val);
    }
    else {
	plist->ch   = 0;
	plist->wave = 0;
    }
    plist++;

    stm_getenv(dev, "ch3_en", &val);
    if (atoi(val)) {
	stm_getenv(dev, "ch3_wave", &val);
	plist->ch   = 3;
	plist->wave = atoi(val);
    }
    else {
	plist->ch   = 0;
	plist->wave = 0;
    }


    int max = count > 3 ? 3 : count;
    plist   = (struct wave_list *)&dev->wl;

    for (int i = 0; i < max; i++) {
	list->ch   = plist->ch;
	list->wave = plist->wave;
	plist++;
	list++;
    }
    return max;
}


#ifdef PRJ_NAME
MODULE_PROJECT(PRJ_NAME);
#endif
#if defined(PRJ_VERSION) && defined(PRJ_PATCHLEVEL) && defined(PRJ_SUBLEVEL)
MODULE_VERSION(PRJ_VERSION "." PRJ_PATCHLEVEL "." PRJ_SUBLEVEL);
#endif

MODULE_BUILD(__DATE__ " " __TIME__);

MODULE_AUTHOR("MenglongWu <MenglongWoo@aliyun.com>");
MODULE_DEPEND("spi_mxs.ko spidev.ko libpthread.so");
MODULE_DEPEND("Board: TR700");
MODULE_DESCRIPTION("The GLink TR700-STM32 communicate interface");
PROG_GITSHA1(__GIT_SHA1__);
